#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__
#ifndef _GUN_SOURCE
#define _GUN_SOURCE
#endif
#include "util.hpp"
#include "level.hpp"
#include<unordered_map>
#include "format.hpp"
#include "looper.hpp"
#include "sink.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>

namespace bitlog
{
   class Logger
   {
   public:
      using ptr = std::shared_ptr<Logger>;
      Logger(const std::string &logger_name,
             LogLevel::value level,
             Formatter::ptr &formatter,
             std::vector<LogSink::ptr> &sinks) : _logger_name(logger_name),
                                                 _limit_level(level),
                                                 _formatter(formatter),
                                                 _sinks(sinks.begin(), sinks.end())//@@@@@@@@@@@@@@@@@@@@@@@@
      {
      }
      const std::string &name(){
         return _logger_name;
      } 
      void debug(const std::string &file, size_t line, const std::string &fmt, ...)//@@@@@@@@@@@@@@@@@@@@@@
      {
         if (LogLevel::value::DEBUG < _limit_level)
         {
            return;
         }
         va_list ap;
         va_start(ap, fmt);
         char *res;
         int ret = vasprintf(&res, fmt.c_str(), ap); // 会动态申请空间给res，所以要free
         if (ret == -1)
         {
            std::cout << "vasprintf failed!!\n";
            return;
         }
         va_end(ap);
         serialize(LogLevel::value::DEBUG, file, line, res);

         free(res);
      }
      void info(const std::string &file, size_t line, const std::string &fmt, ...)
      {
         if (LogLevel::value::INFO < _limit_level)
         {
            return;
         }
         va_list ap;
         va_start(ap,fmt);
         char* res;
         int ret=vasprintf(&res,fmt.c_str(),ap); // 会动态申请空间给res，所以要free
         if (ret == -1)
         {
            std::cout << "vasprintf failed!!\n";
            return;
         }
         va_end(ap);
         serialize(LogLevel::value::INFO, file, line, res);

         free(res);
      }
      void warn(const std::string &file, size_t line, const std::string &fmt, ...)
      {
         if (LogLevel::value::WARN < _limit_level)
         {
            return;
         }
         va_list ap;
         va_start(ap, fmt);
         char *res;
         int ret = vasprintf(&res, fmt.c_str(), ap); // 会动态申请空间给res，所以要free
         if (ret == -1)
         {
            std::cout << "vasprintf failed!!\n";
            return;
         }
         va_end(ap);
         serialize(LogLevel::value::WARN, file, line, res);

         free(res);
      }
      void error(const std::string &file, size_t line, const std::string &fmt, ...)
      {
         if (LogLevel::value::ERROR < _limit_level)
         {
            return;
         }
         va_list ap;
         va_start(ap, fmt);
         char *res;
         int ret = vasprintf(&res, fmt.c_str(), ap); // 会动态申请空间给res，所以要free
         if (ret == -1)
         {
            std::cout << "vasprintf failed!!\n";
            return;
         }
         va_end(ap);
         serialize(LogLevel::value::ERROR, file, line, res);

         free(res);
      }
      void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
      {
         if (LogLevel::value::FATAL < _limit_level)
         {
            return;
         }
         va_list ap;
         va_start(ap, fmt);
         char *res;
         int ret = vasprintf(&res, fmt.c_str(), ap); // 会动态申请空间给res，所以要free
         if (ret == -1)
         {
            std::cout << "vasprintf failed!!\n";
            return;
         }
         va_end(ap);
         serialize(LogLevel::value::FATAL, file, line, res);

         free(res);
      }

   protected:
      void serialize(LogLevel::value level, const std::string &file, size_t line, char *str)
      {
         LogMsg msg(level, line, file, _logger_name, str);

         std::stringstream ss;
         _formatter->format(ss, msg);

         log(ss.str().c_str(), ss.str().size());
      }
      virtual void log(const char *data, size_t len) = 0;

   protected:
      std::mutex _mutex;
      std::string _logger_name;
      std::atomic<LogLevel::value> _limit_level;
      Formatter::ptr _formatter;
      std::vector<LogSink::ptr> _sinks;
   };
   class SyncLogger : public Logger
   {
   public:
      SyncLogger(const std::string &logger_name,
                 LogLevel::value level,
                 Formatter::ptr &formatter,
                 std::vector<LogSink::ptr> &sinks) : Logger(logger_name, level, formatter, sinks)
      {
      }

   protected:
      void log(const char *data, size_t len)
      {
         std::unique_lock<std::mutex> lock(_mutex); // 结束自动解锁
         if (_sinks.empty())
            return;
         for (auto &sink : _sinks)
         {
            sink->log(data, len);
         }
      }
   };

   class AsyncLogger : public Logger
   {
   public:
      AsyncLogger(const std::string &logger_name,
                  LogLevel::value level,
                  Formatter::ptr &formatter,
                  std::vector<LogSink::ptr> &sinks,
                  AsyncType looper_type) :
                  Logger(logger_name, level, formatter, sinks),
                  _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog,this,std::placeholders::_1),looper_type))//bind@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
      {
      }
      void log(const char *data, size_t len) // 将数据写入缓冲区
      {
         _looper->push(data,len);//_looper是线程安全的，所以不用加锁了,但这样理解还不够@@@
      }
      // 设计一个实际落地函数（肩膀缓冲区中的数据落地）
      void realLog(Buffer &buf)//有个隐藏参数this
      {
         if(_sinks.empty())return ;
         for(auto &sink:_sinks){
            sink->log(buf.begin(),buf.readAbleSize());
         }
      }

   private:
      AsyncLooper::ptr _looper;
   };

   enum class LoggerType
   {
      LOGGER_SYNC,
      LOGGER_ASYNC
   };
   /*使用建造者模式来建造*/

   class LoggerBuilder
   {
   public:
      LoggerBuilder() : _logger_type(LoggerType::LOGGER_SYNC),
                        _limit_level(LogLevel::value::DEBUG),
                        _looper_type(AsyncType::ASYNC_SAFE) {}
      void buildLoggerType(LoggerType type) { _logger_type = type; }
      void buildEnableUnSafeAsync(){_looper_type=AsyncType::ASUNC_UNSAFE;}
      void buildLoggerName(const std::string &name) { _logger_name = name; }
      void buildLoggerLevel(LogLevel::value level) { _limit_level = level; }
      void buildFormatter(const std::string &pattern)
      {
         _formatter = std::make_shared<Formatter>(pattern);
      }
      template <typename SinkType, typename... Args>
      void buildSink(Args &&...args)
      {
         LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
         _sinks.push_back(psink);
      }
      virtual Logger::ptr build() = 0;

   protected:
      AsyncType _looper_type;
      LoggerType _logger_type;
      std::string _logger_name;
      LogLevel::value _limit_level;
      Formatter::ptr _formatter;
      std::vector<LogSink::ptr> _sinks;
   };

   class LocalLoggerBuilder : public LoggerBuilder
   {
   public:
      Logger::ptr build() override
      {
         assert(_logger_name.empty() == false);
         if (_formatter.get() == nullptr)//@@@@@@@@@@@@
         {
            _formatter = std::make_shared<Formatter>();
         }
         if (_sinks.empty())
         {
            buildSink<StdoutSink>();
         }
         if (_logger_type == LoggerType::LOGGER_ASYNC)
         {
            return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks,_looper_type);
         }
         return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
      }
   };


   class LoggerManager{
      public:
         static LoggerManager& getInstance(){
            //在c++11之后，针对局部静态变量，编译器在编译的层面实现了线程安全
            //当静态局部变量在没有完成构造之前，其他的线程进入就会阻塞
            static LoggerManager eton;
            return eton;
         }
         void addLogger(Logger::ptr &logger){
            if(hasLogger(logger->name())) return ;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(),logger));

         }
         bool hasLogger(const std::string &name)
         {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_loggers.find(name);
            if(it==_loggers.end()){
               return false;
            }
            return true;
         }
         Logger::ptr getLogger(const std::string &name)
         {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_loggers.find(name);
            if(it==_loggers.end())
            {
               return Logger::ptr();//智能指针的默认构造函数，相当于构造nullptr@@@@@@@@@@@@@@@@@@@@@@@@@
            }
            return it->second;
         }
         Logger::ptr rootLogger(){
            return _root_logger;
         }
      private:
         LoggerManager(){
            std::unique_ptr<bitlog::LoggerBuilder> builder(new bitlog::LocalLoggerBuilder());//不能用全局，不懂，要问@@@@@@@@@@@@@@@@@@@@@@@@
            builder->buildLoggerName("root");
            _root_logger=builder->build();
            _loggers.insert(std::make_pair("root",_root_logger));
         }
      private:
         std::mutex _mutex;
         Logger::ptr _root_logger;//默认日志器
         std::unordered_map<std::string,Logger::ptr> _loggers;
   };
   //设计一个全局日志器的建造者--在局部的基础上增加了一个功能：将日志器添加到单列对象中
   class GlobalLoggerBuilder : public LoggerBuilder
   {
   public:
      Logger::ptr build() override
      {
         assert(_logger_name.empty() == false);
         if (_formatter.get() == nullptr)
         {
            _formatter = std::make_shared<Formatter>();
         }
         if (_sinks.empty())
         {
            buildSink<StdoutSink>();
         }
         Logger::ptr logger;
         if (_logger_type == LoggerType::LOGGER_ASYNC)
         {
            logger= std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks,_looper_type);
         }
         else{
            logger= std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
         }
         LoggerManager::getInstance().addLogger(logger);
         return logger;
      }
   };
}
#endif